`timescale 1ns/1ps
module async_fifo #(
    parameter FIFO_WIDTH = 8,     // 数据位宽
    parameter FIFO_DEPTH = 16,    // FIFO深度
    parameter ADDR_WIDTH = 4      // 地址位宽(log2(FIFO_DEPTH))
)(
    input  wire              wclk,    // 写时钟
    input  wire              rclk,    // 读时钟
    input  wire              rst_n,   // 异步复位
    input  wire              wr_en,   // 写使能
    input  wire              rd_en,   // 读使能
    input  reg  [FIFO_WIDTH-1:0] wr_data, // 写数据
    output reg  [FIFO_WIDTH-1:0] rd_data, // 读数据
    output wire              full,    // 满标志
    output wire              empty    // 空标志

);

// 存储阵列
reg [FIFO_WIDTH-1:0] mem[0:FIFO_DEPTH-1];

// 指针声明
reg [ADDR_WIDTH:0] wr_ptr = 0; // 写指针(额外1bit用于满判断)
reg [ADDR_WIDTH:0] rd_ptr = 0; // 读指针

// Gray码转换
function [ADDR_WIDTH:0] bin2gray;
    input [ADDR_WIDTH:0] bin;
    bin2gray = bin ^ (bin >> 1);
endfunction

// Gray码转换
function [ADDR_WIDTH:0] gray2bin;
    input [ADDR_WIDTH:0] gray;
    integer i;
    begin
        gray2bin[ADDR_WIDTH] = gray[ADDR_WIDTH];  // 最高位直接保留
        for (i = ADDR_WIDTH-1; i >= 0; i = i-1)   // 逐位异或恢复二进制
            gray2bin[i] = gray2bin[i+1] ^ gray[i];
    end
endfunction

// 同步模块
wire [ADDR_WIDTH:0] wr2rd_sync1, wr2rd_sync2;
wire [ADDR_WIDTH:0] rd2wr_sync1, rd2wr_sync2;

always @(posedge rclk) {wr2rd_sync2, wr2rd_sync1} <= {wr2rd_sync1, bin2gray(wr_ptr)};
always @(posedge wclk) {rd2wr_sync2, rd2wr_sync1} <= {rd2wr_sync1, bin2gray(rd_ptr)};

// 空满生成
assign full = (wr_ptr[ADDR_WIDTH] != gray2bin(rd2wr_sync2[ADDR_WIDTH])) && 
    (wr_ptr[ADDR_WIDTH-1:0] == gray2bin(rd2wr_sync2[ADDR_WIDTH-1:0]));
assign empty = (bin2gray(rd_ptr) == gray2bin(wr2rd_sync2));


reg [1:0] reset_counter = 0;
reg [ADDR_WIDTH:0] wr_ptr = 0;

always @(posedge wclk or negedge rst_n) begin
    if (!rst_n) begin
        wr_ptr <= 0;
        reset_counter <= 0;
    end else begin
        if (reset_counter < 2) begin
            reset_counter <= reset_counter + 1;
        end
        else if (wr_en && !full) begin
            mem[wr_ptr[ADDR_WIDTH-1:0]] <= wr_data;
            wr_ptr <= wr_ptr + 1;
        end
    end
end

// 读控制
always @(posedge rclk or negedge rst_n) begin
    if (!rst_n) begin
        rd_ptr <= 0;
    end else if (rd_en && !empty) begin
        rd_data <= mem[rd_ptr[ADDR_WIDTH-1:0]];
        rd_ptr <= rd_ptr + 1;
    end
end

`include "props.sv";

endmodule
